import { AdManager } from "../ads/AdManager";
import { BUNDLE_TYPE_ENUM } from "../base/EnumIndex";
import { Tools } from "../common/Tools";
import { ResManager } from "../manager/ResManager";
import { UIManager } from "../manager/UIManager";
import BaseCar from "../view/BaseCar";
import { ECarDir, ECarState, IStopPark, IStopParkData } from "../view/Const";
import Carport from "./Carport";
import GlobalData from "./GlobalData";
import LevelConfig, { IBoardInfo, ILayerInfo, ILevelConfig, IScrewInfo } from "./LevelConfig";

const { ccclass, property } = cc._decorator;

const BORDER_OFFSET: number = 20;
const MOVE_SPEED: number = 1000;

@ccclass
export default class GameUI extends cc.Component {
    public static instance: GameUI = null;

    @property({ type: cc.SpriteAtlas, tooltip: "车图集" })
    private atlas: cc.SpriteAtlas = null;

    @property({ type: cc.Node, tooltip: "拖尾" })
    public tuowei: cc.Node = null;

    @property({ type: cc.Node, tooltip: "碰撞特效" })
    public pengzhuang: cc.Node = null;

    @property({ type: cc.Prefab, tooltip: "车预制体" })
    private itemCar: cc.Prefab = null;
    @property({ type: cc.Prefab, tooltip: "螺丝预制体" })
    private itemScrew: cc.Prefab = null;
    @property({ type: cc.Prefab, tooltip: "飞螺丝预制体" })
    private itemFlyScrew: cc.Prefab = null;

    @property({ type: cc.Node, tooltip: "螺丝模块父节点" })
    private screwMoudle: cc.Node = null;

    @property({ type: cc.Node, tooltip: "飞螺丝节点" })
    private flys: cc.Node = null;

    @property({ type: cc.Label, tooltip: "螺丝剩余数量" })
    private labRemain: cc.Label = null;

    @property({ type: cc.Node, tooltip: "停车位" })
    private parks: cc.Node = null;

    @property({ type: cc.Node, tooltip: "下方车区域" })
    public cars: cc.Node = null;

    @property({ type: [cc.Node], tooltip: "计算边界点" })
    private borders: cc.Node[] = [];

    @property({ type: cc.Node, tooltip: "用来检测" })
    private rect: cc.Node = null;

    private parkDatas: IStopParkData[] = [];

    private levelConfig: ILevelConfig = null;

    private layerInfos: ILayerInfo[] = [];
    private carports: cc.Node[] = [];

    private _gameData: {
        // levelId: number,
        remainCount: number,
        layerCur: number,
        layerMax: number,
        datas: { color: number, type: number, num: number }[],
        nums: { color: number, num: number }[],
        colors: number[]
    } = { /*levelId: 1,*/ remainCount: 0, layerCur: 0, layerMax: 0, datas: [], nums: [], colors: [] };
    public get gameData() {
        return this._gameData;
    }

    protected async onLoad() {
        GameUI.instance = this;

        cc.macro.ENABLE_MULTI_TOUCH = false;
        cc.director.getPhysicsManager().enabled = true;
        cc.director.getCollisionManager().enabled = true;
        // // 开启物理步长的设置
        cc.director.getPhysicsManager().enabledAccumulator = true;
        // 物理步长，默认 FIXED_TIME_STEP 是 1/60
        cc.PhysicsManager.FIXED_TIME_STEP = 1 / 60;
        cc.director.getPhysicsManager().gravity = cc.v2(0, -1300);
        // cc.director.getPhysicsManager().debugDrawFlags = cc.PhysicsManager.DrawBits.e_aabbBit
        //     | cc.PhysicsManager.DrawBits['e_pairBit']
        //     | cc.PhysicsManager.DrawBits['e_centerOfMassBit']
        //     | cc.PhysicsManager.DrawBits.e_jointBit
        //     | cc.PhysicsManager.DrawBits.e_shapeBit;

        await ResManager.ins.loadLevelBundle(`GameLv`);

        this.initGame();
    }

    private setBorder() {
        const width = this.cars.width;
        const height = this.cars.height;
        const x = 0;//this.cars.x;
        const y = 0;//this.cars.y;
        this.borders[0].setPosition(cc.v2(x, y + height / 2 + BORDER_OFFSET));
        this.borders[1].setPosition(cc.v2(x - width / 2 - BORDER_OFFSET, y));
        this.borders[2].setPosition(cc.v2(x, y - height / 2 - BORDER_OFFSET));
        this.borders[3].setPosition(cc.v2(x + width / 2 + BORDER_OFFSET, y));
    }

    private getGameData() {
        this.parkDatas = Tools.getStorage('parkDatas') || [];
        if (this.parkDatas.length < 1) {
            for (let i = 0; i < 7; i++) {
                const data: IStopParkData = {
                    index: i,
                    isLock: i >= 4,
                    node: null,
                };
                this.parkDatas.push(data);
            }
        }
        // console.log("parkDatas:", this.parkDatas);
    }

    private async initGame() {
        this.layerInfos = [];
        // this.cars.destroyAllChildren();
        // this.screwMoudle.destroyAllChildren();

        this.getGameData();

        // 加载模块资源
        await this.loadRes();

        this.setBorder();
        this.setPark();

        await this.initCarMoudle();
        this.initData();
        this.initScrewMoudle();

        // this.schedule(this.autoFlyToCar.bind(this), 1);
        this.autoFlyToCar();
        this.schedule(this.updateCarport.bind(this), 1);
    }

    public async loadRes() {
        // // 当前关id
        // this.levelID = Tools.getStorage('curLevel') || 1;
        // if (this.levelID > lvMax) {
        //     this.levelID = 2;
        // }
        // Tools.setStorage('curLevel', this.levelID);

        // await ResManager.ins.loadLevelBundle(`k${this.gameData.levelId}`);
    }

    private initData() {
        // 获取配置
        this.levelConfig = LevelConfig.instance.getLevelConfigById(GlobalData.levelId);
        this._gameData = { /*levelId: GlobalData.levelId,*/ remainCount: 0, layerCur: 0, layerMax: 0, datas: [], nums: [], colors: [0, 1, 2, 3, 4, 6, 7] };
        for (let i = 0; i < this._gameData.colors.length; i++) {
            this._gameData.nums.push({ color: this._gameData.colors[i], num: 0 });
        }
        // 颜色打乱
        this._gameData.colors = this._gameData.colors.sort(() => { return 0.5 - Math.random(); });
        console.log("打乱后:", this._gameData.colors);
        let totalCount = 0;
        this.cars.children.forEach((o, i) => {
            const comp = o.getComponent(BaseCar);
            if (comp) {
                // 初始车颜色
                const color = this._gameData.colors[comp.carData.color];
                comp.setData(cc.v3(color, comp.carData.type, comp.carData.dir));
                // 计算螺丝总数
                totalCount += comp.carData.max;
                // 每种颜色螺丝数量
                for (let k = 0; k < this._gameData.nums.length; k++) {
                    if (this._gameData.nums[k].color === comp.carData.color) {
                        this._gameData.nums[k].num += comp.carData.max;
                    }
                }
                // this.gameData.nums[comp.carData.color] += comp.carData.max;
                // 车类型数量(小、中、大)
                this.levelConfig.carNums[comp.carData.type]++;
            }
        });
        // 层数
        this._gameData.layerMax = totalCount / 12;
        // 剩余螺丝计数
        this.updateRemianCount(totalCount);

        // if (totalCount !== this.levelConfig.total) {
        //     console.warn("螺丝孔与螺丝数量不匹配!!!", totalCount, this.levelConfig.total);
        // }

        // console.log(this.levelConfig);
        // console.log(this.gameData);
    }

    private async initCarMoudle() {
        const prefab = await ResManager.ins.loadRes(`car/prefab/car${GlobalData.levelId}`, cc.Prefab, BUNDLE_TYPE_ENUM.LEVEL);
        const node = cc.instantiate(prefab);
        node.parent = this.cars;

        for (let i = node.children.length - 1; i > -1; i--) {
            const car = node.children[i];
            if (car.active) {
                car.parent = this.cars;

                // 车库
                const comp = car.getComponent(Carport);
                if (comp) {
                    this.carports.push(car);
                }

                // 车库出的车
                if (car.y <= this.borders[2].y) {
                    car.active = false;
                }
            }
        }
        node.destroy();
    }

    private async initScrewMoudle() {
        // 创建层
        for (let i = 0; i < this.levelConfig.layers.length; i++) {
            const layer = this.levelConfig.layers[i];
            await this.createLayer(layer);
        }
        // // 剩余螺丝计数
        // this.updateRemianCount(this.levelConfig.total);
    }

    public createGrayLayer() {
        // 创建新层
        GameUI.instance.changeColorToNormal();
        if (GameUI.instance.gameData.layerCur < GameUI.instance.gameData.layerMax) {
            const name = LevelConfig.instance.getLayerName();
            const info = { id: 1, path: name, pos: cc.v2(0, 0)/*cc.v2(Tools.random(-100, 100), Tools.random(-100, 100))*/, boards: [], isGray: true };
            GameUI.instance.createLayer(info);
        }
    }

    public async createLayer(info: ILayerInfo) {
        const prefab = await ResManager.ins.loadRes(`layer/prefab/${info.path}`, cc.Prefab, BUNDLE_TYPE_ENUM.LEVEL);
        const layer = cc.instantiate(prefab);
        layer.parent = this.screwMoudle;
        layer.setPosition(cc.v2(0, 0));
        layer.setSiblingIndex(0);
        layer.opacity = 0;
        layer.children.forEach((box, i) => {
            // 设置刚体状态
            this.scheduleOnce(() => {
                const boxBody = box?.getComponent(cc.RigidBody);
                if (boxBody) {
                    boxBody.gravityScale = 1;
                    boxBody.awake = true;
                }
            }, 1);
            // 设置层颜色
            const boardData = this.getBoardColor();
            this.setLayerColor(box, boardData.color, info.isGray);
            // 创建螺丝
            const screwInfos = this.createScrew(box, boardData, info.isGray);
            info.boards.push({ id: i, color: boardData.color, node: box, screwInfos: screwInfos });
        });
        info.id = this._gameData.layerCur;
        info.layer = layer;
        this._gameData.layerCur++;
        this.layerInfos.push(info);

        // 层动画
        layer.stopAllActions();
        cc.tween(layer).to(0, { opacity: 0 }).to(1, { opacity: 255 }).start();
        // console.log("info:", info);
    }

    public changeColorToNormal() {
        this.layerInfos.forEach((o, i) => {
            const boardInfos = o.boards;
            o.isGray = false;
            o.layer.children.forEach((box, i1) => {
                this.setLayerColor(box, boardInfos[i1].color, false);
                box.children.forEach((screw, i2) => {
                    screw.stopAllActions();
                    cc.tween(screw).to(0.3, { opacity: 255 }).start();
                });
            });
        });
    }

    private setLayerColor(box: cc.Node, color: number, isGray: boolean) {
        // board是白板 需要改颜色
        const board = box.children[0];
        board.opacity = Math.floor(255 * 0.9);
        if (isGray) {
            box.color = new cc.Color().fromHEX("#8E8E8E")
            board.color = new cc.Color().fromHEX("#8E8E8E");
        } else {
            box.color = new cc.Color().fromHEX("#FFFFFF")
            board.color = new cc.Color().fromHEX(GlobalData.colors[color]);
        }
    }

    private createScrew(box: cc.Node, boardData: { num: number, color: number }, isGray: boolean) {
        // 设置分组
        const id = this._gameData.layerCur % 7;
        box.group = `layer${id + 1}`;
        // 螺丝坐标
        const pos = [];
        box.children.forEach((o1, i1) => {
            if (i1 > 1) {
                pos.push(o1.getPosition());
                o1.destroy();
            }
        });
        const screwInfos = [];
        for (let k = 0; k < pos.length; k++) {
            const screw = cc.instantiate(this.itemScrew);
            screw.parent = box;
            screw.name = `${k}`;
            screw.setPosition(pos[k]);
            screw.stopAllActions();
            screw.scale = 0.7;
            screw.opacity = isGray ? 0 : 255;
            // const color = isGray ? "#8E8E8E" : "#FFFFFF";
            // screw.children.forEach((o, i) => {
            //     o.color = new cc.Color().fromHEX(color);
            // });

            // 螺丝动画
            const sprites = screw.children;
            cc.tween(sprites[0]).to(0.5, { opacity: 255 }).start();
            cc.tween(sprites[1]).to(0.5, { opacity: 0, scale: 1 }).start();

            const temp = boardData.num >= 1 ? boardData : this.getBoardColor();
            if (this.isOwesData(temp.color)) {
                screw.destroy();
            } else {
                const screwInfo: IScrewInfo = {
                    id: k,
                    color: temp.color,
                    node: screw,
                    revoluteJoint: null,
                };
                GlobalData.setScrewSprite(screwInfo);
                GlobalData.addRevoluteJoint(box, screwInfo, k);
                screwInfos.push(screwInfo);
            }
            // 更新剩余颜色数量
            for (let i = 0; i < this._gameData.nums.length; i++) {
                const nums = this._gameData.nums[i];
                if (nums.color === temp.color) {
                    nums.num--;
                }
            }
            // console.log("this.gameData.nums--:", this.gameData.nums, temp.id);
        }
        return screwInfos;
    }

    /** 欠螺丝数据 */
    private owesDatas: { color: number, num: number }[] = [];
    private isOwesData(color: number) {
        for (let i = 0; i < this.owesDatas.length; i++) {
            const data = this.owesDatas[i];
            if (data.color === color && data.num > 0) {
                data.num--;
                return true;
            }
        }
        return false;
    }
    private async setOwesData(data: { color: number, num: number }, parkIndex: number, isMore: boolean = false) {
        const temp = this.owesDatas.find((o) => o.color === data.color);
        if (temp) {
            temp.num += data.num;
        } else {
            this.owesDatas.push(data);
        }


        for (let i = 0; i < data.num; i++) {
            const startPos = cc.v2(0, 0);//cc.v2(Tools.random(-200, 200), Tools.random(-100, 100));
            await GlobalData.sleep(isMore ? 50 : 300);
            await this.flyToPark(startPos, parkIndex);
        }
    }

    private async flyToPark(startPos: cc.Vec2, index: number) {
        const end = cc.find("holes", this.parks.children[index]);
        const parkData = this.parkDatas[index];
        try {
            if (!cc.isValid(parkData.node)) {
                return;
            }
            const carComp = parkData.node.getComponent(BaseCar);
            const pos = GlobalData.flyPos[carComp.carData.type][carComp.carData.cur];
            if (!pos) {
                // console.log(this.owesDatas);
                return;
            }
            const endPos = Tools.getToNodePosForNode(end, this.flys);
            // 创建飞的螺丝
            const screw = cc.instantiate(this.itemFlyScrew);
            screw['data'] = { index: index, flyTo: end };
            screw.scale = 0.5;
            screw.parent = this.flys;
            screw.setPosition(startPos);
            // 更新装载数量
            carComp.carData.cur++;
            carComp.updateValue();
            // 剩余螺丝计数
            this.updateRemianCount(-1);
            const flyScrew1 = screw.getChildByName('luosi').getComponent(cc.Sprite);
            const flyScrew2 = screw.getChildByName('luosi_').getComponent(cc.Sprite);
            flyScrew1.spriteFrame = await ResManager.ins.loadRes(`texture/screw/${carComp.carData.color + '0'}`, cc.SpriteFrame, BUNDLE_TYPE_ENUM.GAME_PLAY);
            flyScrew2.spriteFrame = await ResManager.ins.loadRes(`texture/screw/${carComp.carData.color + '1'}`, cc.SpriteFrame, BUNDLE_TYPE_ENUM.GAME_PLAY);

            flyScrew1.node.stopAllActions();
            cc.tween(flyScrew1.node)
                .by(0.2, { angle: 360 }, { easing: "quadIn" })
                .delay(0.3)
                .by(0.3, { angle: -360 }, { easing: "quadOut" })
                .start();
            cc.tween(flyScrew2)
                .to(0.2, { fillRange: -1.5 }, { easing: "quadIn" })
                .delay(0.3)
                .to(0.3, { fillRange: -0.67 }, { easing: "quadOut" })
                .start();
            // console.log('飞行');
            //cc.Easing
            screw.stopAllActions();
            cc.tween(screw)
                .to(0.2, { y: screw.y + 80 }, { easing: "quadIn" })
                .to(0.3, { x: endPos.x + pos.x - 10, y: endPos.y + pos.y + 80 }, { easing: "quadInOut" })
                .to(0.3, { y: endPos.y + pos.y }, { easing: "quadOut" })
                .call(async () => {
                    this.clearSettime();
                    // console.log('飞行结束');
                    screw.parent = screw['data'].flyTo;
                    screw.setPosition(cc.v2(pos.x - 10, pos.y));
                    // 小车离开
                    if (end.children.length >= carComp.carData.max) {
                        // 重置磁铁数据
                        if (this.magnetData.index === index) {
                            this.magnetData = { index: -1, color: -1, isFly: false, node: null };
                        }

                        for (let i = 0; i < this.magnetDatas.length; i++) {
                            const tempData = this.magnetDatas[i];
                            if (tempData.index === index) {
                                tempData.isFly = false;
                                this.magnetDatas.splice(i, 1);
                                break;
                            }
                        }

                        this.animation(parkData.node, false);
                        carComp.setState(ECarState.Null);
                        end.destroyAllChildren();
                        await GlobalData.sleep(100);
                        this.leaveToPark(parkData.node);
                    }
                })
                .start();
        } catch (error) {
            console.log(parkData, index);

            console.log(error);
        }
    }

    // 获取板子颜色
    private getBoardColor() {
        try {
            const colorNums: { color: number, num: number }[] = [];
            this._gameData.nums.forEach((o, i) => {
                // colorNums.push({ id: i, num: o });
                colorNums.push(o);
            });
            colorNums.sort((a, b) => { return b.num - a.num });
            // console.log("colorNums:", colorNums);

            const randoms: { color: number, num: number }[] = [];
            for (let i = 0; i < 1; i++) {
                if (colorNums[i].num > 0) {
                    randoms.push(colorNums[i]);
                }
            }
            // console.log("randoms:", randoms);

            const index = Math.floor(Math.random() * randoms.length);
            if (randoms[index].num <= 0) {
                console.warn("数量为0~");
            }
            return randoms[index];
        } catch (error) {
            console.log(error);
        }
        return null;
    }

    // 剩余螺丝计数
    private async updateRemianCount(add: number) {
        this._gameData.remainCount += add;
        this.labRemain.string = `${this._gameData.remainCount}`;
        // console.log("剩余螺丝数:", this.gameData.remainCount);

        if (this._gameData.remainCount <= 0) {
            await GlobalData.sleep(2000);
            console.log("过关~");
            // this.restartGame();
            GlobalData.levelId++;
            if (GlobalData.levelId > 2) {
                GlobalData.levelId = 2;
            }
            UIManager.ins.showPop("WinUI", BUNDLE_TYPE_ENUM.GAME_PLAY);
        }
    }

    // 从车库创建车
    private updateCarport() {
        for (let i = 0; i < this.carports.length; i++) {
            const comp = this.carports[i].getComponent(Carport);
            comp.checkIntersect();
            if (comp.isHad() && !comp.checkIntersect()) {
                comp.num--;
                this.createCar(comp);
            }
        }
    }

    private createCar(carport: Carport) {
        // 应该从车库出的车
        const cars = [];
        this.cars.children.forEach((o, i) => {
            const comp = o.getComponent(BaseCar);
            if (comp && !o.active && o.y <= this.borders[2].y) {
                cars.push(o);
            }
        });

        if (cars.length <= 0) {
            console.log("剩余0");
            return;
        }
        
        // 颜色、大小、方向
        const car = cars[Math.floor(Math.random() * cars.length)];
        car.active = true;
        car.setSiblingIndex(0);
        car.setPosition(carport.node.getPosition());
        const carComp = car.getComponent(BaseCar);
        carComp.setData(cc.v3(carComp.data.x, carComp.data.y, carport.dir));
        carComp.setState(ECarState.Null);
        car.stopAllActions();
        let data = {};
        switch (carport.dir) {
            case ECarDir.Up:
                data = { y: carport.node.y + 150 };
                break;
            case ECarDir.Down:
                data = { y: carport.node.y - 150 };
                break;
            case ECarDir.Left:
                data = { x: carport.node.x - 150 };
                break;
            case ECarDir.Right:
                data = { x: carport.node.x + 150 };
                break;
        }
        cc.tween(car).to(0.3, data).call(() => {
            carComp.setState(ECarState.Click);
        }).start();
    }

    /**
     * 获取停车位信息
     * @returns 
     */
    public getStopPark() {
        const data: IStopPark = { index: -1, start: cc.v2(), end: cc.v2() };
        for (let i = 0; i < this.parkDatas.length; i++) {
            let park = this.parkDatas[i];
            if (!park.isLock && !park.node) {
                data.index = i;
                break;
            }
        }

        if (data.index === -1) {
            return null;
        }

        const node = this.parks.children[data.index];
        data.start = cc.v2(node.x - 20, this.borders[0].y);
        data.end = cc.v2(node.x, node.y + this.parks.y - this.cars.y); // TODO 跟停车位和车节点有关系
        return data;
    }

    public setRectSize(node: cc.Node, dir: ECarDir) {
        this.rect.width = node.width - 20;
        this.rect.height = node.height - 20;
        this.rect.setPosition(node.getPosition());
        switch (dir) {
            case ECarDir.Up:
                this.rect.height = this.borders[0].y - node.y;
                this.rect.y += this.rect.height / 2 - BORDER_OFFSET;
                break;
            case ECarDir.Down:
                this.rect.height = node.y - this.borders[2].y;
                this.rect.y -= (this.rect.height / 2 - BORDER_OFFSET);
                break;
            case ECarDir.Left:
                this.rect.width = node.x - this.borders[1].x;
                this.rect.x -= (this.rect.width / 2 - BORDER_OFFSET);
                break;
            case ECarDir.Right:
                this.rect.width = this.borders[3].x - node.x;
                this.rect.x += this.rect.width / 2 - BORDER_OFFSET;
                break;
        }

        // 从碰撞组中排除自己
        const cars = [];
        for (let i = 0; i < this.cars.children.length; i++) {
            const car = this.cars.children[i];
            if (car !== node && car.name !== "rect") {
                cars.push(car);
            }
        }
        return cars;
    }

    /**
     * 获取被遮挡?
     * @param node 
     * @param dir 
     * @returns 
     */
    public getIsCover(node: cc.Node, dir: ECarDir) {
        // 设置碰撞检测图尺寸
        const cars = this.setRectSize(node, dir);
        // 检测碰撞
        // const covers = [];
        let cover = null;
        for (let i = 0; i < cars.length; i++) {
            if (!cc.isValid(cars[i])) continue;
            const comp = cars[i].getComponent(BaseCar);
            if (!comp) continue;
            if (comp.carData.state === ECarState.Click) {
                if (GlobalData.intersect(cars[i], this.rect)) {
                    switch (dir) {
                        case ECarDir.Up:
                            if (cars[i].y > node.y) {
                                cover = !cover ? cars[i] : (cover.y < cars[i].y ? cover : cars[i]);
                            }
                            break;
                        case ECarDir.Down:
                            if (cars[i].y < node.y) {
                                cover = !cover ? cars[i] : (cover.y > cars[i].y ? cover : cars[i]);
                            }
                            break;
                        case ECarDir.Left:
                            if (cars[i].x < node.x) {
                                cover = !cover ? cars[i] : (cover.x > cars[i].x ? cover : cars[i]);
                            }
                            break;
                        case ECarDir.Right:
                            if (cars[i].x > node.x) {
                                cover = !cover ? cars[i] : (cover.x < cars[i].x ? cover : cars[i]);
                            }
                            break;
                    }
                }
            }
        }
        // console.log(cover);
        return cover;
    }

    public setParkDatas(index: number, carNode: cc.Node) {
        if (!this.parkDatas[index]) {
            return;
        }
        this.parkDatas[index].node = carNode;
        // console.log(this.parkDatas);
    }

    /**
     * 驶离
     * @param node 
     */
    private leaveToPark(node: cc.Node) {
        const comp = node.getComponent(BaseCar);
        const park = comp.park;
        const distance = Math.abs(node.x - 270) / MOVE_SPEED;
        node.active = true;
        const car = cc.find("car", this.parks.children[park.index]).getComponent(cc.Sprite);
        car.node.active = false;
        node.stopAllActions();
        cc.tween(node).sequence(
            cc.moveTo(0.1, cc.v2(park.start.x, park.start.y)),
            cc.callFunc(() => {
                comp.setDir(ECarDir.Right);
                this.setParkDatas(park.index, null);
            }),
            cc.spawn(
                cc.rotateTo(0.15, 0),
                cc.moveTo(distance, cc.v2(270, this.borders[0].y)),
            ),
            cc.callFunc(() => {
                node.destroy();
            }),
        ).start();
    }

    /**
     * 停到停车位过程
     * @param node 
     * @param state 
     */
    private stopToPark(node: cc.Node, state: ECarState) {
        const comp = node.getComponent(BaseCar);
        const park = comp.park;
        const data: { distance: number, end: cc.Vec2, callback: Function } = { distance: 0, end: cc.v2(), callback: null };
        comp.setState(state);
        switch (state) {
            case ECarState.Find:
                {
                    // console.log("ECarState.Find");
                    comp.setDir(node.x > park.start.x ? ECarDir.Left : ECarDir.Right);

                    data.distance = Math.abs(node.x - park.start.x) / MOVE_SPEED;
                    data.end = cc.v2(park.start.x, node.y);
                    data.callback = () => {
                        this.stopToPark(node, ECarState.Stop);
                    }
                    node.angle = 0;
                }
                break;
            case ECarState.Stop:
                {
                    comp.setDir(ECarDir.Up);

                    data.distance = Math.abs(node.y - park.end.y) / MOVE_SPEED;
                    data.end = cc.v2(park.end.x, park.end.y);
                    data.callback = async () => {
                        // this.setParkDatas(park.index, node);
                        // setTimeout(() => {
                        //     this.leaveToPark(node);
                        // }, 3000);
                        this.animation(node, true);
                    }
                    node.angle = -13;
                }
                break;
        }

        node.stopAllActions();
        cc.tween(node).sequence(
            cc.moveTo(data.distance, data.end),
            cc.callFunc(() => {
                data.callback && data.callback();
                data.callback = null;
            }),
        ).start();
    }

    /**
     * 开盖动画
     * @param node 车节点
     */
    private async animation(node: cc.Node, isOpen: boolean) {
        if (!cc.isValid(node)) return;
        const comp = node.getComponent(BaseCar);
        node.active = false;
        const car = cc.find("car", this.parks.children[comp.park.index]).getComponent(cc.Sprite);
        car.node.active = true;
        // const url = `car${color}_${dir}_${type}.`;
        const url = `car${comp.carData.color + 1}_${comp.carData.type}_kai${isOpen ? 1 : 2}.`;
        car.spriteFrame = this.atlas.getSpriteFrame(url);
        await GlobalData.sleep(50);
        const url1 = `car${comp.carData.color + 1}_${comp.carData.type}_kai${isOpen ? 2 : 1}.`;
        car.spriteFrame = this.atlas.getSpriteFrame(url1);
        if (!isOpen) {
            await GlobalData.sleep(50);
            node.active = true;
            car.node.active = false;
        }
    }

    /**
     * 从下方停车区域出发
     * @param node 
     * @param dir 
     */
    public gotoPark(node: cc.Node) {
        const comp = node.getComponent(BaseCar);
        const dir = comp.carData.dir;
        const data: { stop: cc.Node, distance: number, end: cc.Vec2, callback: Function } = { stop: null, distance: 0, end: cc.v2(), callback: null };
        data.stop = this.borders[dir];
        switch (dir) {
            case ECarDir.Up:
            case ECarDir.Down:
                {
                    data.distance = Math.abs(node.y - data.stop.y) / MOVE_SPEED;
                    data.end = cc.v2(node.x, data.stop.y);
                    data.callback = () => {
                        if (dir === ECarDir.Up) {
                            this.stopToPark(node, ECarState.Find);
                        } else {
                            if (node.x > 0) {
                                comp.setDir(ECarDir.Right);
                                this.gotoPark(node);
                            } else {
                                comp.setDir(ECarDir.Left);
                                this.gotoPark(node);
                            }
                        }
                    }
                }
                break;
            case ECarDir.Left:
            case ECarDir.Right:
                {
                    data.distance = Math.abs(node.x - data.stop.x) / MOVE_SPEED;
                    data.end = cc.v2(data.stop.x, node.y);
                    data.callback = () => {
                        comp.setDir(ECarDir.Up);
                        this.gotoPark(node);
                    }
                }
                break;
        }
        node.stopAllActions();
        cc.tween(node).sequence(
            cc.moveTo(data.distance, data.end),
            cc.callFunc(() => {
                data.callback && data.callback();
                data.callback = null;
            }),
        ).start();
    }

    private setPark() {
        this.parks.children.forEach((o, i) => {
            const video = cc.find("video", o);
            const car = cc.find('car', o);
            video.active = this.parkDatas[i].isLock;
            car.active = false;
            // console.log("this.parkDatas[i].isLock:", this.parkDatas[i].isLock);
        });
    }

    private isEnd: boolean = false;
    private stValue: number = -1;
    protected update(dt: number): void {
        // 失败判定
        if (this.isEnd) return;
        this.isEnd = this.isGameEnd();
        if (this.isEnd) {
            this.stValue = setTimeout(() => {
                // this.restartGame();
                this.showLoseUI();
            }, 2000);
        }
    }

    private clearSettime() {
        clearTimeout(this.stValue);
        this.stValue = -1;
        this.isEnd = false;
    }

    private showLoseUI() {
        if (!this.parkDatas) return;
        for (let i = 0; i < this.parkDatas.length; i++) {
            const parkData = this.parkDatas[i];
            if (parkData.isLock) {
                UIManager.ins.showPop("ReviveUI", BUNDLE_TYPE_ENUM.GAME_PLAY, { type: 0 });
                return;
            }
        }

        UIManager.ins.showPop("ReviveUI", BUNDLE_TYPE_ENUM.GAME_PLAY, { type: 1 });
        // UIManager.ins.showPop("LoseUI", BUNDLE_TYPE_ENUM.GAME_PLAY);
    }

    public revive(type: number) {
        // type = 1;
        switch (type) {
            case 0:     // 复活(解锁车位)
                {
                    this.magent(null, false);
                    for (let i = 0; i < this.parkDatas.length; i++) {
                        const parkData = this.parkDatas[i];
                        if (parkData.isLock) {
                            this.isEnd = false;
                            this.unlockPark(i);
                            break;
                        }
                    }
                }
                break;
            case 1:     // 复活(装满所有车)
                {
                    this.magent(null, true);
                }
                break;
        }
    }

    private isGameEnd() {
        if (!this.parkDatas || this.parkDatas.length <= 0) return false;
        let count1 = 0;
        let count2 = 0;
        for (let i = 0; i < this.parkDatas.length; i++) {
            const parkData = this.parkDatas[i];
            if (!parkData.isLock) {
                count1++;
            }

            if (cc.isValid(parkData.node)) {
                const comp = parkData.node.getComponent(BaseCar);
                if (comp.carData.state === ECarState.Stop) {
                    count2++;
                }
            }
        }
        return count1 === count2;
    }

    public restartGame() {
        if (this.layerInfos) {
            for (let i = 0; i < this.layerInfos.length; i++) {
                const layerInfo = this.layerInfos[i];
                for (let k = 0; k < layerInfo.boards.length; k++) {
                    const boardInfo = layerInfo.boards[k];
                    for (let j = 0; j < boardInfo.screwInfos.length; j++) {
                        const screwInfo = boardInfo.screwInfos[j];
                        if (screwInfo && screwInfo.node) {
                            screwInfo.node.destroy();
                            screwInfo.node = null;
                        }
                    }
                }
            }
        }

        UIManager.ins.close();
        UIManager.ins.showUI("GameUI", BUNDLE_TYPE_ENUM.GAME_PLAY);
    }

    private count: number = 0;
    private async autoFlyToCar() {
        this.count = 0;
        if (this.layerInfos && !this.magnetData.isFly) {
            for (let i = 0; i < this.layerInfos.length; i++) {
                const layerInfo = this.layerInfos[i];
                if (this.magnetData.index === -1 && this.magnetDatas.length <= 0) {
                    if (!layerInfo.isGray) {
                        for (let k = 0; k < layerInfo.boards.length; k++) {
                            const boardInfo = layerInfo.boards[k];
                            for (let j = 0; j < boardInfo.screwInfos.length; j++) {
                                const screwInfo = boardInfo.screwInfos[j];
                                if (screwInfo?.node?.active) {
                                    await this.checkScrew(boardInfo, screwInfo);
                                }
                            }
                        }
                    }
                } else {
                    for (let k = 0; k < layerInfo.boards.length; k++) {
                        const boardInfo = layerInfo.boards[k];
                        for (let j = 0; j < boardInfo.screwInfos.length; j++) {
                            const screwInfo = boardInfo.screwInfos[j];
                            await this.checkScrew(boardInfo, screwInfo);
                        }
                    }
                }
            }
        }

        await GlobalData.sleep(50);
        let callback = (magnetData, isMore: boolean) => {
            if (magnetData) {
                const comp = magnetData.node.getComponent(BaseCar);
                const data = { color: comp.carData.color, num: comp.carData.max - comp.carData.cur };
                // console.log("data.num:", data.num);
                if (data.num > 0) {
                    magnetData.isFly = true;
                    this.setOwesData(data, magnetData.index, isMore);

                    console.log("this.owesDatas:", data, magnetData.index);
                    console.log("差:", data.num, magnetData.index);
                }
            }
        }

        if (this.magnetData && !this.magnetData.isFly && this.magnetData.index !== -1) {
            callback && callback(this.magnetData, false);
            callback = null;
        }

        if (this.magnetDatas) {
            for (let i = this.magnetDatas.length - 1; i > -1; i--) {
                const temp = this.magnetDatas[i];
                if (!temp?.isFly) {
                    callback && callback(this.magnetDatas[i], true);
                    callback = null;
                    // } else {
                    //     console.log(temp, temp.isFly);
                }
            }
        }

        await GlobalData.sleep(50);
        this.autoFlyToCar();
    }


    private async checkScrew(boardInfo: IBoardInfo, screwInfo: IScrewInfo) {
        let callback = async (comp: BaseCar, i: number) => {
            this.count++;
            const screwInfos = boardInfo.screwInfos;
            const indexToRemove: number | undefined = screwInfos.findIndex(obj => obj.node === screwInfo.node);
            if (indexToRemove !== undefined) {
                // 使用splice方法从数组中移除该对象  
                screwInfos.splice(indexToRemove, 1);
            }

            await GlobalData.sleep(this.count * 50);
            await this.flyScrew(screwInfo, i);
        }

        if (this.magnetData.index === -1 && this.magnetDatas.length <= 0) {
            if (!GlobalData.isScrewHide(screwInfo)) {
                for (let i = 0; i < this.parkDatas.length; i++) {
                    const parkData = this.parkDatas[i];
                    if (!parkData || !cc.isValid(parkData.node)) continue;
                    const comp = parkData.node.getComponent(BaseCar);
                    if (comp && !comp.isFull() && comp.carData.color === screwInfo.color && comp.state === ECarState.Stop) {
                        callback && await callback(comp, i);
                        callback = null;
                        break;
                    }
                }
            }
        } else {
            if (this.magnetData.index != -1) {
                if (this.magnetData && !this.magnetData.node) {
                    console.warn(this.magnetData);
                }

                const comp = this.magnetData.node.getComponent(BaseCar);
                if (comp && !comp.isFull() && comp.carData.color === screwInfo.color && comp.state === ECarState.Stop) {
                    callback && await callback(comp, this.magnetData.index);
                    callback = null;
                }
            } else {
                for (let i = 0; i < this.magnetDatas.length; i++) {
                    const temp = this.magnetDatas[i];
                    const comp = temp.node.getComponent(BaseCar);
                    if (comp && !comp.isFull() && comp.carData.color === screwInfo.color && comp.state === ECarState.Stop) {
                        callback && await callback(comp, temp.index);
                        callback = null;
                    }
                }
            }
        }
    }

    private async flyScrew(screwInfo: IScrewInfo, index: number) {
        if (!screwInfo.node || !cc.isValid(screwInfo.node)) {
            console.log("不存在~", screwInfo.node);
            return;
        }
        // try {
        const startPos = Tools.getToNodePosForNode(screwInfo.node, this.flys);
        GlobalData.removeRevoluteJoint(screwInfo);
        screwInfo.node.active = false;
        await this.flyToPark(startPos, index);
        screwInfo.node.destroy();
        // } catch (error) {
        //     console.log(screwInfo.node);

        //     console.log(error);
        // }
    }

    private unlockPark(index: number) {
        if (this.parkDatas[index].isLock) {
            // console.log("播放视频");
            this.parkDatas[index].isLock = false;
            const video = cc.find("video", this.parks.children[index]);
            video.active = false;
        }
    }

    public magent(callback: Function, isRevive: boolean = false) {
        if (!isRevive) {
            if (this.magnetData.index !== -1) {
                console.log("飞~");
                return;
            }

            for (let i = 0; i < this.parkDatas.length; i++) {
                const parkData = this.parkDatas[i];
                if (parkData.node) {
                    const comp = parkData.node.getComponent(BaseCar);
                    if (comp && !comp.isFull()) {
                        this.magnetData = { index: i, color: comp.carData.color, isFly: false, node: parkData.node };
                        callback && callback();
                        callback = null;
                        break;
                    }
                }
            }
        } else {
            for (let i = 0; i < this.parkDatas.length; i++) {
                const parkData = this.parkDatas[i];
                if (parkData.node) {
                    const comp = parkData.node.getComponent(BaseCar);
                    if (comp && !comp.isFull()) {
                        const data = { index: i, color: comp.carData.color, isFly: false, node: parkData.node };
                        this.magnetDatas.push(data);
                    }
                }
            }
            console.log("this.magnetDatas:", this.magnetDatas);
        }
    }

    public change() {
        const cars = [[], [], []];
        const colors = [[], [], []];
        this.cars.children.forEach((o, i) => {
            const comp = o.getComponent(BaseCar);
            if (comp && comp.carData.state === ECarState.Click) {
                cars[comp.carData.type].push(o);
                colors[comp.carData.type].push(comp.carData.color);
            }
        });
        // console.log("1111:", colors);
        for (let i = 0; i < colors.length; i++) {
            colors[i] = colors[i].sort(() => { return 0.5 - Math.random(); });
        }
        // console.log("2222:", colors);
        for (let i = 0; i < cars.length; i++) {
            for (let k = 0; k < cars[i].length; k++) {
                const car = cars[i][k];
                const comp = car.getComponent(BaseCar);
                comp.setData(cc.v3(colors[i][k], comp.data.y, comp.data.z));
            }
        }
    }

    private isClick: boolean = false;
    private magnetData: { index: number, color: number, isFly: boolean, node: cc.Node } = { index: -1, color: -1, isFly: false, node: null };
    private magnetDatas: { index: number, color: number, isFly: boolean, node: cc.Node }[] = [];
    private onBtnsClicked(event: cc.Event, data: cc.Event.EventCustom) {
        const name = event.target.name;
        switch (name) {
            case "btnSetting":
                {
                    UIManager.ins.showPop("SettingUI", BUNDLE_TYPE_ENUM.GAME_PLAY, { isMain: true });
                }
                break;
            case "btnMagnet":   // 磁铁
                {
                    // UIManager.ins.showPop("MagnetUI", BUNDLE_TYPE_ENUM.GAME_PLAY);
                    if (this.isClick) { return; }
                    this.isClick = true;
                    AdManager.showVideoAd(() => {
                        this.isClick = false;
                        this.magent(null, false);
                    }, () => {
                        this.isClick = false;
                    });
                }
                break;
            case "btnPos":     // 解锁车位
                {
                    if (this.isClick) { return; }
                    this.isClick = true;
                    AdManager.showVideoAd(() => {
                        this.isClick = false;
                        this.clearSettime();
                        const nodes = event.target.parent.children as cc.Node[];
                        const index = nodes.indexOf(event.target);
                        // console.log("解锁:", index);
                        this.unlockPark(index);
                    }, () => {
                        this.isClick = false;
                    });
                }
                break;
            case "btnRefresh": // 刷新
                {
                    if (this.isClick) { return; }
                    this.isClick = true;
                    AdManager.showVideoAd(() => {
                        this.isClick = false;
                        this.change();
                    }, () => {
                        this.isClick = false;
                    });
                }
                break;
        }
        // console.log("onReviveClicked()===>按钮:", name);
    }
}